package com.beta.cust.bind.utils;

import com.beta.cat.utils.JsonUtil;
import com.beta.cust.bind.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import java.io.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Auther: pcc
 * @Date: 2024/4/1 09:22
 * @Description:
 */
@Slf4j
public class CrmUtil {

    /**
     * 请求ESB服务
     *
     * @param docStr
     * @param svcId
     * @param url
     * @return 对应的body部分
     * @throws Exception
     */
    public static CrmCustDetailVO queryDetailFromCrm(String docStr, String svcId, String url)
            throws Exception {
        String result = sendXmlToESB(docStr, svcId, url);
        log.info("sendXmlToESB result:{}", result);
        return parseDoc2Cust(result);
    }

    /**
     * 请求ESB服务
     *
     * @param docStr
     * @param svcId
     * @param url
     * @return 对应的body部分
     * @throws Exception
     */
    public static String sendSms(String docStr, String svcId, String url)
            throws Exception {
        String result = sendXmlToESB(docStr, svcId, url);
        log.info("sendXmlToESB result:{}", result);
        return parseDoc2Sms(result);
    }

    /**
     * 请求ESB服务
     *
     * @param doc
     * @param svcId
     * @param url
     * @return
     * @throws Exception
     */
    public static String sendXmlToESB(Document doc, String svcId, String url)
            throws Exception {
        DOMSource requestMsg = new DOMSource(doc);
        String ns = "http://esb.xjrccb.com/" + svcId + "wsdl";
        QName serviceName = new QName(ns, "TradeService");
        QName portName = new QName(ns, "TradePort");
        Service service = Service.create(serviceName);
        service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, url + svcId);
        Dispatch dispatch = service.createDispatch(portName, Source.class, Service.Mode.PAYLOAD);
        log.info("sendXmlToESB requestParam:{}", JsonUtil.toJson(requestMsg));
        Source responseMsg = (Source) dispatch.invoke(requestMsg);
        TransformerFactory transFactory = TransformerFactory.newInstance();
        Transformer transformer = transFactory.newTransformer();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        StreamResult result = new StreamResult();
        result.setOutputStream(baos);
        transformer.transform(responseMsg, result);
        return baos.toString("utf-8");
    }

    /**
     * 请求ESB服务
     *
     * @param xml
     * @param svcId
     * @param url
     * @return
     * @throws Exception
     */
    public static String sendXmlToESB(String xml, String svcId, String url)
            throws Exception {
        Document doc = parseXml2Doc(xml);
        DOMSource requestMsg = new DOMSource(doc);
        String ns = "http://esb.xjrccb.com/" + svcId + "wsdl";
        QName serviceName = new QName(ns, "TradeService");
        QName portName = new QName(ns, "TradePort");
        Service service = Service.create(serviceName);
        service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, url + svcId);
        Dispatch dispatch = service.createDispatch(portName, Source.class, Service.Mode.PAYLOAD);
        log.info("sendXmlToESB requestParam:{}", JsonUtil.toJson(requestMsg));
        Source responseMsg = (Source) dispatch.invoke(requestMsg);
        TransformerFactory transFactory = TransformerFactory.newInstance();
        Transformer transformer = transFactory.newTransformer();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        StreamResult result = new StreamResult();
        result.setOutputStream(baos);
        transformer.transform(responseMsg, result);
        return baos.toString("utf-8");
    }

    /**
     *
     * @param xml
     * @return
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws SAXException
     */
    private static Document parseXml2Doc(String xml) throws IOException, ParserConfigurationException, SAXException {
        if(StringUtils.isEmpty(xml)){
            return null;
        }
        byte[] buf = xml.getBytes("utf-8");
        InputStream in = new ByteArrayInputStream(buf);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        return factory.newDocumentBuilder().parse(in);
    }

    /**
     * 转换detail对象
     * @param xml
     * @return
     * @throws Exception
     */
    public static CrmCustDetailVO parseDoc2Cust(String xml) throws Exception {
        Document doc = parseXml2Doc(xml);
        // 获取根元素
        Element root = doc.getDocumentElement();
        // 解析 svcHead
        Element svcHeadElement = (Element) root.getElementsByTagName("ns:svcHead").item(0);
        SvcHead svcHead = parseSvcHead(svcHeadElement);
        if(null ==svcHead || svcHead.getRspCode() != 200){
            log.error("parseDoc2Cust resp code 200 head:{}",JsonUtil.toJson(svcHead));
            return null;
        }
        // 解析 appBody
        Element appBodyElement = (Element) root.getElementsByTagName("ns:appBody").item(0);
        return parseCustData((Element) appBodyElement.getElementsByTagName("ns:data").item(0));
    }

    /**
     * 转换sms发送返回值
     * @param xml
     * @return
     * @throws Exception
     */
    public static String parseDoc2Sms(String xml) throws Exception {
        Document doc = parseXml2Doc(xml);
        // 获取根元素
        Element root = doc.getDocumentElement();
        // 解析 svcHead
        Element svcHeadElement = (Element) root.getElementsByTagName("ns:svcHead").item(0);
        SvcHead svcHead = parseSvcHead(svcHeadElement);
        if(null != svcHead && svcHead.getRspCode() == 0){
            log.error("parseDoc2Cust resp code 200 head:{}",JsonUtil.toJson(svcHead));
            return StringUtils.EMPTY;
        }
        return svcHead.getRspIfn();
    }

    /**
     * 生成查询detail参数
     * @param paramMap
     * @return
     */
    public static String buildDetailDocStr(Map<String, String> paramMap) {
        StringBuilder detailBuilder = new StringBuilder();
        detailBuilder.append("<ns:reqt\n");
        detailBuilder.append("    xmlns:ns=\"http://esb.xjrccb.com/").append(paramMap.get("svcId")).append("\">\n");
        detailBuilder.append("    <ns:svcHead>\n");
        detailBuilder.append("        <ns:SvcId>").append(paramMap.get("svcId")).append("</ns:SvcId>\n");
        detailBuilder.append("        <ns:OptId>01</ns:OptId>\n");
        detailBuilder.append("        <ns:VerNo>").append(paramMap.get("version")).append("</ns:VerNo>\n");
        detailBuilder.append("        <ns:CsmId>").append(paramMap.get("cmsId")).append("</ns:CsmId>\n");
        detailBuilder.append("        <ns:CsmTms>").append(LocalDateTime.now().toString()).append("</ns:CsmTms>\n");
        detailBuilder.append("        <ns:CsmSeqNo>").append(paramMap.get("csmSeqNo")).append("</ns:CsmSeqNo>\n");
        detailBuilder.append("    </ns:svcHead>\n");
        detailBuilder.append("    <ns:appBody>\n");
        detailBuilder.append("        <ns:mgrPhone>").append(paramMap.get("mgrPhone")).append("</ns:mgrPhone>\n");
        detailBuilder.append("        <ns:cstPhone>").append(paramMap.get("cstPhone")).append("</ns:cstPhone>\n");
        detailBuilder.append("    </ns:appBody>\n");
        detailBuilder.append("</ns:reqt>");
        return detailBuilder.toString();
    }

    /**
     * 生成sms参数
     * @param paramMap
     * @return
     */
    public static String buildSmsDocStr(Map<String,String> paramMap){
        StringBuilder smsBuilder = new StringBuilder();
        smsBuilder.append("<ns:reqt xmlns:ns=\"http://esb.xjrccb.com/").append(paramMap.get("svcId")).append("\">\n");
        smsBuilder.append("    <ns:svcHead>\n");
        smsBuilder.append("        <ns:SvcId>").append(paramMap.get("svcId")).append("</ns:SvcId>\n");
        smsBuilder.append("        <ns:OptId>01</ns:OptId>\n");
        smsBuilder.append("        <ns:VerNo>").append(paramMap.get("version")).append("</ns:VerNo>\n");
        smsBuilder.append("        <ns:CsmId>").append(paramMap.get("cmsId")).append("</ns:CsmId>\n");
        smsBuilder.append("        <ns:CsmTms>").append(LocalDateTime.now().toString()).append("</ns:CsmTms>\n");
        smsBuilder.append("        <ns:CsmSeqNo>").append(paramMap.get("csmSeqNo")).append("</ns:CsmSeqNo>\n");
        smsBuilder.append("    </ns:svcHead>\n");
        smsBuilder.append("    <ns:extHead/>\n");
        smsBuilder.append("    <ns:appHead>\n");
        smsBuilder.append("        <ns:BsnNo>").append(paramMap.get("bsnNo")).append("</ns:BsnNo>\n");
        smsBuilder.append("        <ns:ReqBrcNo>").append(paramMap.get("reqBrcNo")).append("</ns:ReqBrcNo>\n");
        smsBuilder.append("        <ns:AuthNo>").append(paramMap.get("authNo")).append("</ns:AuthNo>\n");
        smsBuilder.append("        <ns:BpkSendTms></ns:BpkSendTms>\n");
        smsBuilder.append("    </ns:appHead>\n");
        smsBuilder.append("    <ns:appBody>\n");
        smsBuilder.append("        <ns:MblNo>").append(paramMap.get("mobile")).append("</ns:MblNo>\n");
        smsBuilder.append("        <ns:SmsCott>").append(paramMap.get("text")).append("</ns:SmsCott>\n");
        smsBuilder.append("        <ns:OpenCardBrc>").append(paramMap.get("reqBrcNo")).append("</ns:OpenCardBrc>\n");
        smsBuilder.append("    </ns:appBody>\n");
        smsBuilder.append("</ns:reqt>");
        return smsBuilder.toString();
    }

    /**
     * 返回头解析处理
     * @param svcHeadElement
     * @return
     */
    private static SvcHead parseSvcHead(Element svcHeadElement) {
        SvcHead svcHead = new SvcHead();
        svcHead.setSvcId(getElementTextContent(svcHeadElement, "ns:SvcId"));
        svcHead.setOptId(getElementTextContent(svcHeadElement, "ns:OptId"));
        svcHead.setEsbSvcSeqNo(getElementTextContent(svcHeadElement, "ns:EsbSvcSeqNo"));
        svcHead.setPvdId(getElementTextContent(svcHeadElement, "ns:PvdId"));
        svcHead.setRspSrc(getElementTextContent(svcHeadElement, "ns:RspSrc"));
        svcHead.setRspCode(getElementTextContentInteger(svcHeadElement, "ns:RspCode"));
        svcHead.setRspIfn(getElementTextContent(svcHeadElement, "ns:RspIfn"));
        svcHead.setPvdSeqNo(getElementTextContent(svcHeadElement, "ns:PvdSeqNo"));
        svcHead.setEsbTms(getElementTextContent(svcHeadElement, "ns:EsbTms"));
        return svcHead;
    }

    /**
     * 认证详情对象转换
     * @param dataElement
     * @return
     */
    private static CrmCustDetailVO parseCustData(Element dataElement) {
        CrmCustDetailVO data = new CrmCustDetailVO();
        data.setCstId(getElementTextContent(dataElement, "ns:cstId"));
        data.setCstNm(getElementTextContent(dataElement, "ns:cstNm"));
        data.setCstSex(getElementTextContent(dataElement, "ns:cstSex"));
        data.setCstPhone(getElementTextContent(dataElement, "ns:cstPhone"));
        data.setNation(getElementTextContent(dataElement, "ns:nation"));
        data.setMgrId(getElementTextContent(dataElement, "ns:mgrId"));
        data.setMgrNm(getElementTextContent(dataElement, "ns:mgrNm"));
        data.setMgrPhone(getElementTextContent(dataElement, "ns:mgrPhone"));
        data.setInstNm(getElementTextContent(dataElement, "ns:instNm"));
        data.setDqMsg1(getElementTextContent(dataElement, "ns:dqMsg1"));
        data.setDqMsg2(getElementTextContent(dataElement, "ns:dqMsg2"));
        data.setLcMsg1(getElementTextContent(dataElement, "ns:lcMsg1"));
        data.setLcMsg2(getElementTextContent(dataElement, "ns:lcMsg2"));
        data.setAssetSum(getElementTextContentDouble(dataElement, "ns:assetSum"));

        // 解析 lbls
        List<String> lbls = new ArrayList<>();
        NodeList lblNodes = dataElement.getElementsByTagName("ns:lbls");
        for (int i = 0; i < lblNodes.getLength(); i++) {
            lbls.add(lblNodes.item(i).getTextContent());
        }
        data.setLbls(lbls);
        // 解析 asset
        Element assetElement = (Element) dataElement.getElementsByTagName("ns:asset").item(0);
        CrmAssetVO asset = new CrmAssetVO();
        asset.setDmdepBal(getElementTextContentDouble(assetElement, "ns:dmdepBal"));
        asset.setTmdepBal(getElementTextContentDouble(assetElement, "ns:tmdepBal"));
        asset.setChrtcBal(getElementTextContentDouble(assetElement, "ns:chrtcBal"));
        asset.setShrAmtBal(getElementTextContentDouble(assetElement, "ns:shrAmtBal"));
        data.setAsset(asset);

        return data;
    }

    /**
     * 获取指定tag的节点值
     * @param parentElement
     * @param tagName
     * @return String
     */
    private static String getElementTextContent(Element parentElement, String tagName) {
        NodeList nodeList = parentElement.getElementsByTagName(tagName);
        return nodeList.getLength()!=0 ? nodeList.item(0).getTextContent() : StringUtils.EMPTY;
    }

    /**
     * 获取指定tag的节点值
     * @param parentElement
     * @param tagName
     * @return Double
     */
    private static Double getElementTextContentDouble(Element parentElement, String tagName) {
        String str = getElementTextContent(parentElement,tagName);
        return StringUtils.isEmpty(str) ? null : Double.valueOf(str);
    }

    /**
     * 获取指定tag的节点值
     * @param parentElement
     * @param tagName
     * @return Integer
     */
    private static Integer getElementTextContentInteger(Element parentElement, String tagName) {
        String str = getElementTextContent(parentElement,tagName);
        return StringUtils.isEmpty(str) ? null : Integer.valueOf(str);
    }

}
